package com.xdcplus.web.service.wip.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xdcplus.etl.schedule.annotation.Job;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.exceptions.XdcWebException;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;

import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.sms.api.SmsRemote;
import com.xdcplus.web.common.pojo.bo.WipPieceNetWeightBO;
import com.xdcplus.web.common.pojo.dto.bd.BdWetWeightAlarmConfigFilterDTO;
import com.xdcplus.web.common.pojo.dto.bd.BdWetWeightTargetFilterDTO;
import com.xdcplus.web.common.pojo.dto.sms.SmsDTO;
import com.xdcplus.web.common.pojo.vo.bd.BdWetWeightAlarmConfigVO;
import com.xdcplus.web.common.pojo.vo.bd.BdWetWeightTargetVO;
import com.xdcplus.web.mapper.wip.WipWetWeightAlarmRecordMapper;
import com.xdcplus.web.common.pojo.entity.wip.WipWetWeightAlarmRecord;
import com.xdcplus.web.common.pojo.dto.wip.WipWetWeightAlarmRecordDTO;
import com.xdcplus.web.common.pojo.dto.wip.WipWetWeightAlarmRecordFilterDTO;
import com.xdcplus.web.common.pojo.vo.wip.WipWetWeightAlarmRecordVO;
import com.xdcplus.web.common.pojo.query.wip.WipWetWeightAlarmRecordQuery;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.mp.utils.PageableUtils;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.web.service.bd.BdWetWeightAlarmConfigService;
import com.xdcplus.web.service.bd.BdWetWeightTargetService;
import org.springframework.transaction.annotation.Transactional;

import com.xdcplus.web.service.wip.WipWetWeightAlarmRecordService;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

/**
 * (WipWetWeightAlarmRecord)表服务实现类
 *
 * @author Zhecheng.Ren
 * @since 2024-10-22 15:14:13
 */
@Slf4j
@Service("wipWetWeightAlarmRecordService")
public class WipWetWeightAlarmRecordServiceImpl extends BaseServiceImpl<WipWetWeightAlarmRecordMapper, WipWetWeightAlarmRecord, WipWetWeightAlarmRecord, WipWetWeightAlarmRecordVO> implements WipWetWeightAlarmRecordService {

    @Resource
    protected WipWetWeightAlarmRecordMapper wipWetWeightAlarmRecordMapper;
    @Resource
    protected BdWetWeightTargetService bdWetWeightTargetService;
    @Resource
    protected BdWetWeightAlarmConfigService bdWetWeightAlarmConfigService;
    @Resource
    protected SmsRemote smsRemote;

    private static final String TYPE = "markdown";

    private static final String MESSAGE_TEMPLATE_CODE = "WET_WEIGHT_ALARM_SEND";

    private final static String HANDLER_NAME = "handleWetWeightAlarm";

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveWipWetWeightAlarmRecord(WipWetWeightAlarmRecordDTO wipWetWeightAlarmRecordDTO) {

        WipWetWeightAlarmRecord wipWetWeightAlarmRecord = new WipWetWeightAlarmRecord();
        BeanUtil.copyProperties(wipWetWeightAlarmRecordDTO, wipWetWeightAlarmRecord);

        this.save(wipWetWeightAlarmRecord);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void updateWipWetWeightAlarmRecord(WipWetWeightAlarmRecordDTO wipWetWeightAlarmRecordDTO) {

        WipWetWeightAlarmRecord wipWetWeightAlarmRecord = this.getById(wipWetWeightAlarmRecordDTO.getId());
        if (ObjectUtil.isNull(wipWetWeightAlarmRecord)) {
            log.error("updateWipWetWeightAlarmRecord() The WipWetWeightAlarmRecord does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        BeanUtil.copyProperties(wipWetWeightAlarmRecordDTO, wipWetWeightAlarmRecord);

        this.updateById(wipWetWeightAlarmRecord);
    }

    @Override
    public Boolean saveOrUpdateBatch(List<WipWetWeightAlarmRecord> wipWetWeightAlarmRecordList) {

        wipWetWeightAlarmRecordList.forEach(wipWetWeightAlarmRecord -> {
            WipWetWeightAlarmRecord wipWetWeightAlarmRecordParam = new WipWetWeightAlarmRecord();
            wipWetWeightAlarmRecordParam.setId(wipWetWeightAlarmRecord.getId());
            if (ObjectUtil.isNotNull(wipWetWeightAlarmRecord.getId())) {
                wipWetWeightAlarmRecord.setId(wipWetWeightAlarmRecord.getId());
                LambdaUpdateWrapper<WipWetWeightAlarmRecord> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(WipWetWeightAlarmRecord::getId, wipWetWeightAlarmRecord.getId());
                update(wipWetWeightAlarmRecord, lambdaUpdate);
            } else {
                save(wipWetWeightAlarmRecord);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<WipWetWeightAlarmRecordDTO> wipWetWeightAlarmRecordDTOList) {

        List<WipWetWeightAlarmRecord> wipWetWeightAlarmRecordList = BeanUtils.copyProperties(wipWetWeightAlarmRecordDTOList, WipWetWeightAlarmRecord.class);
        return saveOrUpdateBatch(wipWetWeightAlarmRecordList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void deleteWipWetWeightAlarmRecordLogical(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        WipWetWeightAlarmRecord wipWetWeightAlarmRecord = this.getById(id);

        if (ObjectUtil.isNull(wipWetWeightAlarmRecord)) {
            log.error("deleteWipWetWeightAlarmRecord() The WipWetWeightAlarmRecord does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void deleteWipWetWeightAlarmRecordByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        List<String> idList = Arrays.asList(ids.split(","));
        if (CollectionUtil.isEmpty(idList)) {
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        idList.forEach(id -> {
            WipWetWeightAlarmRecord wipWetWeightAlarmRecord = this.getById(id);
            if (ObjectUtil.isNull(wipWetWeightAlarmRecord)) {
                log.error("deleteWipWetWeightAlarmRecord() The WipWetWeightAlarmRecord does not exist or has been deleted");
                throw new XdcWebException(ResponseEnum.ERROR);
            }
        });

        this.removeByIds(idList);
    }

    private List<WipWetWeightAlarmRecord> queryWipWetWeightAlarmRecordList(WipWetWeightAlarmRecordFilterDTO wipWetWeightAlarmRecordFilterDTO) {
        WipWetWeightAlarmRecordQuery wipWetWeightAlarmRecordQuery = BeanUtil.copyProperties(wipWetWeightAlarmRecordFilterDTO, WipWetWeightAlarmRecordQuery.class);

        return wipWetWeightAlarmRecordMapper.queryWipWetWeightAlarmRecord(wipWetWeightAlarmRecordQuery);
    }

    @Override
    public List<WipWetWeightAlarmRecordVO> queryWipWetWeightAlarmRecordVOList(WipWetWeightAlarmRecordFilterDTO wipWetWeightAlarmRecordFilterDTO) {
        return this.objectConversion(queryWipWetWeightAlarmRecordList(wipWetWeightAlarmRecordFilterDTO));
    }

    @Override
    public PageVO<WipWetWeightAlarmRecordVO> queryWipWetWeightAlarmRecord(WipWetWeightAlarmRecordFilterDTO wipWetWeightAlarmRecordFilterDTO) {
        PageVO<WipWetWeightAlarmRecordVO> pageVO = new PageVO<>();

        if (wipWetWeightAlarmRecordFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(wipWetWeightAlarmRecordFilterDTO.getCurrentPage(), wipWetWeightAlarmRecordFilterDTO.getPageSize(),
                    wipWetWeightAlarmRecordFilterDTO.getOrderType(), wipWetWeightAlarmRecordFilterDTO.getOrderField());
        }

        List<WipWetWeightAlarmRecord> wipWetWeightAlarmRecordList = queryWipWetWeightAlarmRecordList(wipWetWeightAlarmRecordFilterDTO);

        PageInfo<WipWetWeightAlarmRecord> pageInfo = new PageInfo<>(wipWetWeightAlarmRecordList);
        PropertyUtils.copyProperties(pageInfo, pageVO, this.objectConversion(wipWetWeightAlarmRecordList));

        return pageVO;
    }

    @Override
    public WipWetWeightAlarmRecordVO queryWipWetWeightAlarmRecordById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public WipWetWeightAlarmRecordVO queryByBayCodeAndRoadNum(String bayCode, Integer roadNum) {
        WipWetWeightAlarmRecord wipWetWeightAlarmRecord = wipWetWeightAlarmRecordMapper.queryByBayCodeAndRoadNum(bayCode, roadNum);
        return this.objectConversion(wipWetWeightAlarmRecord);
    }

    @Job(HANDLER_NAME)
    @Override
    public void handleWetWeightAlarm() {
        // 1. 查询所有丝印湿重阈值配置
        List<BdWetWeightTargetVO> bdWetWeightTargetVOS = bdWetWeightTargetService.queryBdWetWeightTargetVOList(new BdWetWeightTargetFilterDTO());
        // 2. 查询所有丝印道次的最新的湿重记录
        List<WipPieceNetWeightBO> wipPieceNetWeightBOS = wipWetWeightAlarmRecordMapper.queryNetWeightLatest();
        List<BdWetWeightAlarmConfigVO> bdWetWeightAlarmConfigVOS = bdWetWeightAlarmConfigService.queryBdWetWeightAlarmConfigVOList(new BdWetWeightAlarmConfigFilterDTO());
        // 3. 根据所有丝印湿重配置的阈值匹配数据库中最新的湿重记录
        bdWetWeightTargetVOS.forEach(bdWetWeightTargetVO -> wipPieceNetWeightBOS.forEach(wipPieceNetWeightBO -> {
            if (bdWetWeightTargetVO.getBayCode().equals(wipPieceNetWeightBO.getBayCode())
                    && bdWetWeightTargetVO.getRoadNum().equals(wipPieceNetWeightBO.getRoadNum())
                    && CollectionUtil.isNotEmpty(bdWetWeightAlarmConfigVOS)) {
                handleAlarm(bdWetWeightTargetVO, wipPieceNetWeightBO, bdWetWeightAlarmConfigVOS);
            }
        }));
    }

    private void handleAlarm(BdWetWeightTargetVO bdWetWeightTargetVO, WipPieceNetWeightBO wipPieceNetWeightBO, List<BdWetWeightAlarmConfigVO> bdWetWeightAlarmConfigVOS) {

        Double lowerLimit = bdWetWeightTargetVO.getLowerLimit();
        Double upperLimit = bdWetWeightTargetVO.getUpperLimit();
        Double wetWeight = wipPieceNetWeightBO.getWetWeight();

        String bayCode = wipPieceNetWeightBO.getBayCode();
        Integer roadNum = wipPieceNetWeightBO.getRoadNum();
        String toolCode = wipPieceNetWeightBO.getToolCode();
        WipWetWeightAlarmRecord wipWetWeightAlarmRecord = wipWetWeightAlarmRecordMapper.queryByBayCodeAndRoadNum(bayCode, roadNum);
        // 如果当前值不在阈值范围内，则发送报警信息
        if (wetWeight < lowerLimit || wetWeight > upperLimit) {
            if (ObjectUtil.isNull(wipWetWeightAlarmRecord)) {
                BdWetWeightAlarmConfigVO alarmConfig = getAlarmConfig(bdWetWeightAlarmConfigVOS, 0);
                wipWetWeightAlarmRecord = new WipWetWeightAlarmRecord();
                wipWetWeightAlarmRecord.setAlarmLevel(alarmConfig.getAlarmLevel());
                wipWetWeightAlarmRecord.setAlarmStatus(NumberConstant.ONE);
                wipWetWeightAlarmRecord.setAlarmTime(new Timestamp(DateUtil.current()));
                wipWetWeightAlarmRecord.setBayCode(bayCode);
                wipWetWeightAlarmRecord.setRoadNum(roadNum);
                wipWetWeightAlarmRecordMapper.insert(wipWetWeightAlarmRecord);

                sendSms(bayCode, roadNum, toolCode, upperLimit, lowerLimit, wetWeight, alarmConfig);
            } else {
                BdWetWeightAlarmConfigVO alarmConfig = getAlarmConfig(bdWetWeightAlarmConfigVOS, wipWetWeightAlarmRecord.getAlarmLevel());
                wipWetWeightAlarmRecord.setAlarmLevel(alarmConfig.getAlarmLevel());
                wipWetWeightAlarmRecord.setAlarmTime(new Timestamp(DateUtil.current()));
                wipWetWeightAlarmRecord.setAlarmStatus(NumberConstant.ONE);
                wipWetWeightAlarmRecordMapper.updateById(wipWetWeightAlarmRecord);

                sendSms(bayCode, roadNum, toolCode, upperLimit, lowerLimit, wetWeight, alarmConfig);
            }
        } else {
            if (ObjectUtil.isNull(wipWetWeightAlarmRecord)) {
                wipWetWeightAlarmRecord = new WipWetWeightAlarmRecord();
                wipWetWeightAlarmRecord.setAlarmLevel(NumberConstant.ZERO);
                wipWetWeightAlarmRecord.setAlarmStatus(NumberConstant.ZERO);
                wipWetWeightAlarmRecord.setCancelTime(new Timestamp(DateUtil.current()));
                wipWetWeightAlarmRecord.setBayCode(bayCode);
                wipWetWeightAlarmRecord.setRoadNum(roadNum);

                wipWetWeightAlarmRecordMapper.insert(wipWetWeightAlarmRecord);
            } else {
                wipWetWeightAlarmRecord.setAlarmLevel(NumberConstant.ZERO);
                wipWetWeightAlarmRecord.setAlarmStatus(NumberConstant.ZERO);
                wipWetWeightAlarmRecord.setCancelTime(new Timestamp(DateUtil.current()));
                wipWetWeightAlarmRecordMapper.updateById(wipWetWeightAlarmRecord);
            }
        }

    }

    private BdWetWeightAlarmConfigVO getAlarmConfig(List<BdWetWeightAlarmConfigVO> bdWetWeightAlarmConfigVOS, Integer alarmLevel) {
        if (alarmLevel == 0) {
            return bdWetWeightAlarmConfigVOS.get(0);
        }
        for (int i = 0; i < bdWetWeightAlarmConfigVOS.size(); i++) {
            if (Objects.equals(alarmLevel, bdWetWeightAlarmConfigVOS.get(i).getAlarmLevel())) {
                if (i == bdWetWeightAlarmConfigVOS.size() - 1) {
                    return bdWetWeightAlarmConfigVOS.get(i);
                } else {
                    return bdWetWeightAlarmConfigVOS.get(i + 1);
                }
            }
        }
        return bdWetWeightAlarmConfigVOS.get(0);
    }

    private void sendSms(String bayCode, Integer roadNum, String toolCode, Double upperLimit, Double lowerLimit, Double wetWeight, BdWetWeightAlarmConfigVO bdWetWeightAlarmConfig) {

        JSONObject result = new JSONObject();
        result.put("bayCode", bayCode);
        result.put("roadNum", roadNum);
        result.put("toolCode", toolCode);
        result.put("upperLimit", upperLimit);
        result.put("lowerLimit", lowerLimit);
        result.put("wetWeight", wetWeight);
        result.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        String receiveUsers = bdWetWeightAlarmConfig.getReceiveUsers();
        String receivePositions = bdWetWeightAlarmConfig.getReceivePositions();
        String receiveGroups = bdWetWeightAlarmConfig.getReceiveGroups();

        String[] userIds;
        if (StrUtil.isNotBlank(receiveUsers)) {
            userIds = receiveUsers.split(",");
        } else {
            userIds = new String[]{};
        }
        String[] groupCodes;
        if (StrUtil.isNotBlank(receiveGroups)) {
            groupCodes = receiveGroups.split(",");
        } else {
            groupCodes = new String[]{};
        }
        String[] positionIds;
        if (StrUtil.isNotBlank(receivePositions)) {
            positionIds = receivePositions.split(",");
        } else {
            positionIds = new String[]{};
        }

        List<Long> userIdList = Arrays.stream(userIds).mapToLong(Long::parseLong).boxed().collect(Collectors.toList());
        List<Long> positionIdList = Arrays.stream(positionIds).mapToLong(Long::parseLong).boxed().collect(Collectors.toList());

        SmsDTO smsDTO = new SmsDTO.Builder()
                .addTitle("丝印湿重异常")
                .addContentType(TYPE)
                .addGroupCodes(Arrays.asList(groupCodes))
                .addUserIds(userIdList)
                .addPositionIds(positionIdList)
                .addMessageTemplateCode(MESSAGE_TEMPLATE_CODE).addParameters(result).build();
        smsRemote.sendMessageV2(JSONObject.parseObject(JSONObject.toJSONString(smsDTO)));
    }
}
